chore: add github sponsors on supporters#8531
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
👋 Codeowner Review RequestThe following codeowners have been identified for the changed files: Team reviewers: @nodejs/nodejs-website Please review the changes when you have a chance. Thank you! 🙏 |
This comment was marked as off-topic.
This comment was marked as off-topic.
📦 Build Size ComparisonSummary
Changes➕ Added Assets (2)
➖ Removed Assets (2)
|
06c283f to
46d49e7
Compare
Signed-off-by: Sebastian Beltran <bjohansebas@gmail.com>
Signed-off-by: Sebastian Beltran <bjohansebas@gmail.com>
Signed-off-by: Sebastian Beltran <bjohansebas@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Sebastian Beltran <bjohansebas@gmail.com>
| organization(login: "nodejs") { | ||
| sponsorshipsAsMaintainer (first: 100, includePrivate: false, after: "${cursor}", activeOnly: false) { |
There was a problem hiding this comment.
definitely, I’d prefer that we only show sponsors that are active, but why do we want to show everyone? see #8268.
There was a problem hiding this comment.
wdyt @nodejs/nodejs-website @nodejs/marketing ?
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Sebastian Beltran <bjohansebas@gmail.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for all 4 issues found in the latest run.
- ✅ Fixed: GraphQL cursor interpolated as string "null" on first request
- The sponsorship query now serializes
cursorwithJSON.stringify(cursor), so the first request sends GraphQLnullinstead of the string "null".
- The sponsorship query now serializes
- ✅ Fixed: Duplicate
n.sponsorEntityfallback provides no additional coverage- Sponsor extraction was consolidated to
node.sponsor || node.sponsorEntity, removing the duplicated fallback in both mapping paths.
- Sponsor extraction was consolidated to
- ✅ Fixed: Component loses OpenCollective profile links by switching to
url- The supporters component now passes
profile || urltoAvatar, restoring OpenCollective profile links while keeping website URLs as fallback.
- The supporters component now passes
- ✅ Fixed: Missing deduplication between sponsorship and activity queries
- GitHub sponsors are now added through a deduplicating helper keyed by sponsor identity so overlaps between sponsorships and activity events no longer duplicate entries.
Or push these changes by commenting:
@cursor push 77dce1aa43
Preview (77dce1aa43)
diff --git a/apps/site/components/Common/Supporters/index.tsx b/apps/site/components/Common/Supporters/index.tsx
--- a/apps/site/components/Common/Supporters/index.tsx
+++ b/apps/site/components/Common/Supporters/index.tsx
@@ -11,13 +11,13 @@
const SupportersList: FC<SupportersListProps> = ({ supporters }) => (
<div className="flex max-w-full flex-wrap items-center justify-center gap-1">
- {supporters.map(({ name, image, url }) => (
+ {supporters.map(({ name, image, profile, url }) => (
<Avatar
nickname={name}
fallback={getAcronymFromString(name)}
image={image}
key={name}
- url={url}
+ url={profile || url}
/>
))}
</div>
diff --git a/apps/site/next-data/generators/supportersData.mjs b/apps/site/next-data/generators/supportersData.mjs
--- a/apps/site/next-data/generators/supportersData.mjs
+++ b/apps/site/next-data/generators/supportersData.mjs
@@ -46,7 +46,26 @@
}
const sponsors = [];
+ const seenSponsorKeys = new Set();
+ const addSponsor = node => {
+ const s = node.sponsor || node.sponsorEntity; // support different field names
+ const key = s?.id ?? s?.login ?? s?.url ?? s?.name ?? s?.avatarUrl;
+ if (key && seenSponsorKeys.has(key)) {
+ return;
+ }
+ if (key) {
+ seenSponsorKeys.add(key);
+ }
+
+ sponsors.push({
+ name: s?.name || s?.login || null,
+ image: s?.avatarUrl || null,
+ url: s?.url || null,
+ source: 'github',
+ });
+ };
+
// Fetch sponsorship pages
let cursor = null;
@@ -64,18 +83,8 @@
}
const { nodes, pageInfo } = nodeRes;
- const mapped = nodes.map(n => {
- const s = n.sponsor || n.sponsorEntity || n.sponsorEntity; // support different field names
- return {
- name: s?.name || s?.login || null,
- image: s?.avatarUrl || null,
- url: s?.url || null,
- source: 'github',
- };
- });
+ nodes.forEach(addSponsor);
- sponsors.push(...mapped);
-
if (!pageInfo.hasNextPage) {
break;
}
@@ -96,18 +105,8 @@
}
const { nodes } = nodeRes;
- const mapped = nodes.map(n => {
- const s = n.sponsor || n.sponsorEntity || n.sponsorEntity; // support different field names
- return {
- name: s?.name || s?.login || null,
- image: s?.avatarUrl || null,
- url: s?.url || null,
- source: 'github',
- };
- });
+ nodes.forEach(addSponsor);
- sponsors.push(...mapped);
-
return sponsors;
}
@@ -115,7 +114,7 @@
return `
query {
organization(login: "nodejs") {
- sponsorshipsAsMaintainer (first: 100, includePrivate: false, after: "${cursor}", activeOnly: false) {
+ sponsorshipsAsMaintainer (first: 100, includePrivate: false, after: ${JSON.stringify(cursor)}, activeOnly: false) {
nodes {
sponsor: sponsorEntity {
...on User {This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
…in supportersData.mjs
…ships and donations queries
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 492c9ed. Configure here.
|
|
||
| const { nodes, pageInfo } = nodeRes; | ||
| const mapped = nodes.map(n => { | ||
| const s = n.sponsor || n.sponsorEntity; // support different field names |
There was a problem hiding this comment.
GraphQL alias makes n.sponsorEntity fallback unreachable dead code
Low Severity
The || n.sponsorEntity fallback in both fetchSponsorshipsQuery and fetchDonationsQuery is unreachable. In SPONSORSHIPS_QUERY, the GraphQL alias sponsor: sponsorEntity ensures the response field is always sponsor — sponsorEntity never appears in the JSON response. In DONATIONS_QUERY, the field is natively named sponsor. So n.sponsorEntity is always undefined, making the fallback dead code with a misleading comment.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 492c9ed. Configure here.
|
X-posting from Slack... the fine-grained token I generated did not work: I attempted switching the preview to a classic token with no permissions set, which also did not work: Given our security posture for this project is that anyone can submit a PR that will immediately be built on Vercel, anyone could extract this token, so I do not believe it is safe to grant We could attempt using a fine-grained token that has an expiration date, to comply with the org requirement (even though the fine-grained token resource owner is not the org), but that then becomes a yearly maintenance burden for us to ensure it is regenerated before it expires and breaks this feature. I feel like we may be at an impasse here, unless we want to try a classic token with those permissions, but production only, so that this feature will not work in preview deployments? |
|
I have generated a new classic token for @openjs-vercel with just the With that scope applied to the token, https://nodejs-org-git-githubsponsors-openjs.vercel.app/en/about/partners is showing sponsors 🎉 |
|
Cool, so @nodejs/nodejs-website and @nodejs/web-infra, could you please review it? |
Signed-off-by: Brian Muenzenmeyer <brian.muenzenmeyer@gmail.com>
bmuenzenmeyer
left a comment
There was a problem hiding this comment.
one clarifying point between a comment and a query
otherwise looks great!
| first: 100 | ||
| includePrivate: false | ||
| after: $cursor | ||
| activeOnly: false |
There was a problem hiding this comment.
activeOnly sounds contrary to the comment in the calling function, where we filter out active members. just something to confirm one way or the other




Description
Note that there’s no REST API for GitHub Sponsors, only a GraphQL API. I’m still working on this.
Preview:

Validation
Related Issues
closes #8199
Check List
pnpm formatto ensure the code follows the style guide.pnpm testto check if all tests are passing.pnpm buildto check if the website builds without errors.